home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 June / ccd0605.iso / Software / Freeware / Programare / zoomsearch / zoomsearch.exe / {app} / scripts / PHP or ASP / search.php < prev   
PHP Script  |  2005-03-10  |  52KB  |  1,475 lines

  1. <?php
  2. // ----------------------------------------------------------------------------
  3. // Zoom Search Engine 4.0 (10/3/2005)
  4. // PHP search front-end
  5. // A fast custom website search engine using pre-indexed data files.
  6. // Copyright (C) Wrensoft 2000 - 2004
  7. //
  8. // This script is designed for PHP 4.0 + only.
  9. //
  10. // email: zoom@wrensoft.com
  11. // www: http://www.wrensoft.com
  12. // ----------------------------------------------------------------------------
  13.  
  14. if(strcmp('4.0.0', phpversion()) > 0)
  15.     die("This version of the script requires PHP 4.0.0 or higher.<br />");
  16.  
  17. require("settings.php");
  18.  
  19. // Check for dependent files
  20. if (!file_exists("settings.php") || !file_exists("zoom_wordmap.zdat") || !file_exists("zoom_dictionary.zdat")
  21.     || !file_exists("zoom_pages.zdat") || !file_exists("zoom_titles.zdat"))
  22. {
  23.     print("<b>Zoom files missing error:</b> Zoom is missing one or more of the required index data files.<br />Please make sure the generated index files are uploaded to the same path as this search script.<br />");
  24.     return;
  25. }
  26.  
  27. if ($Spelling == 1 && !file_exists("zoom_spelling.zdat"))
  28.     print("<b>Zoom files missing error:</b> Zoom is missing the 'zoom_spelling.zdat' file required for the Spelling Suggestion feature which has been enabled.<br />");
  29.  
  30. // ----------------------------------------------------------------------------
  31. // Settings
  32. // ----------------------------------------------------------------------------
  33.  
  34. // The options available in the dropdown menu for number of results
  35. // per page
  36. $PerPageOptions = array(10, 20, 50, 100);
  37.  
  38. /*
  39. // For foreign language support, setlocale may be required on the server for
  40. // wildcards and highlighting to work. Uncomment the following lines and specify
  41. // the appropriate locale information
  42. //if (setlocale(LC_ALL, "ru_RU.cp1251") == false) // for russian
  43. //  print("Failed to change locale setting or locale setting invalid");
  44. */
  45.  
  46. // ----------------------------------------------------------------------------
  47. // Parameter initialisation
  48. // ----------------------------------------------------------------------------
  49.  
  50. // Send HTTP header to define meta charset
  51. if (isset($Charset) && strlen($Charset) > 0)
  52.     header("Content-Type: text/html; charset=" . $Charset);
  53.  
  54. // For versions of PHP before 4.1.0
  55. // we will emulate the superglobals by creating references
  56. // NOTE: references created are NOT superglobals
  57. if (!isset($_SERVER) && isset($HTTP_SERVER_VARS))
  58.     $_SERVER = &$HTTP_SERVER_VARS;
  59. if (!isset($_GET) && isset($HTTP_GET_VARS))
  60.     $_GET = &$HTTP_GET_VARS;
  61. if (!isset($_POST) && isset($HTTP_POST_VARS))
  62.     $_POST = &$HTTP_POST_VARS;
  63.  
  64. // check if magic_quotes are on for Get/Post/Cookie variables
  65. // and fix accordingly (we don't use cookies so we leave them out)
  66. if (get_magic_quotes_gpc() == 1) {
  67.     while (list($key, $value) = each($_GET))
  68.         $_GET["$key"] = stripslashes($value);
  69.     while (list($key, $value) = each($_POST))
  70.         $_POST["$key"] = stripslashes($value);
  71. }
  72.  
  73. // check magic_quotes for runtime stuff (reading from files, etc)
  74. if (get_magic_quotes_runtime() == 1)
  75.     set_magic_quotes_runtime(0);
  76.  
  77. // we use the method=GET and 'query' parameter now (for sub-result pages etc)
  78. if (isset($_GET['zoom_query'])) {
  79.     $query = $_GET['zoom_query'];
  80. }
  81. else
  82.     $query = "";
  83.  
  84. // number of results per page, defaults to 10 if not specified
  85. if (isset($_GET['zoom_per_page']))
  86.     $per_page = $_GET['zoom_per_page'];
  87. else
  88.     $per_page = 10;
  89.  
  90. // current result page number, defaults to the first page if not specified
  91. $NewSearch = 0;
  92. if (isset($_GET['zoom_page']))
  93.     $page = $_GET['zoom_page'];
  94. else
  95. {
  96.     $page = 1;
  97.     $NewSearch = 1;
  98. }
  99.  
  100. // AND operator.
  101. // 1 if we are searching for ALL terms
  102. // 0 if we are searching for ANY terms (default)
  103. if (isset($_GET['zoom_and']))
  104.     $and = $_GET['zoom_and'];
  105. elseif (isset($DefaultToAnd) && $DefaultToAnd == 1)
  106.     $and = 1;
  107. else
  108.     $and = 0;
  109.  
  110. // for category support
  111. if (isset($_GET['zoom_cat']))
  112.     $cat = $_GET['zoom_cat'];
  113. else
  114.     $cat = -1;  // search all categories
  115.  
  116. // for sorting options
  117. // zero is default (relevance)
  118. // 1 is sort by date (if Date/Time is available)
  119. if (isset($_GET['zoom_sort']))
  120.     $sort = $_GET['zoom_sort'];
  121. else
  122.     $sort = 0;
  123.  
  124. if (isset($LinkBackURL) == false || strlen($LinkBackURL) < 1)
  125.     $SelfURL = $_SERVER['PHP_SELF'];
  126. else
  127.     $SelfURL = $LinkBackURL;
  128.  
  129. // init. link target string
  130. $target = "";
  131. if ($UseLinkTarget == 1)
  132.     $target = " target=\"" . $LinkTarget . "\" ";
  133.  
  134. // ----------------------------------------------------------------------------
  135. // Functions
  136. // ----------------------------------------------------------------------------
  137.  
  138. function PrintEndOfTemplate($template)
  139. {
  140.     global $ZoomInfo;
  141.     global $STR_POWEREDBY;
  142.     global $template_line;
  143.  
  144.     //Let others know about Zoom.
  145.     if ($ZoomInfo == 1)
  146.         print("<center><p><small>" . $STR_POWEREDBY . " <a href=\"http://www.wrensoft.com/zoom/\" target=\"_blank\"><b>Zoom Search Engine</b></a></small></p></center>");
  147.  
  148.     //Print out the end of the template
  149.     while ($template_line < count($template)) {
  150.         print($template[$template_line]);
  151.         $template_line++;
  152.     }
  153. }
  154.  
  155. function PrintHighlightDescription($line)
  156. {
  157.     global $HighlightColor;
  158.     global $SearchWords;
  159.     global $numwords;
  160.     global $SearchAsSubstring;
  161.  
  162.     $res = $line;
  163.  
  164.     for ($i = 0; $i < $numwords; $i++)
  165.     {
  166.         if (strlen($SearchWords[$i]) < 1)
  167.             continue;
  168.  
  169.         // replace with marker text, assumes [;:] and [:;] is not the search text...
  170.         if ($SearchAsSubstring == 1)
  171.             $res = preg_replace("/(" .$SearchWords[$i] . ")/i", "[;:]$1[:;]", $res);
  172.         else
  173.             $res = preg_replace("/(\W|\A|\b)(" .$SearchWords[$i] . ")(\W|\Z|\b)/i", "$1[;:]$2[:;]$3", $res);
  174.     }
  175.     // replace the marker text with the html text
  176.     // this is to avoid finding previous <span>'ed text.
  177.     $res = str_replace("[;:]", "<span class=\"highlight\">", $res);
  178.     $res = str_replace("[:;]", "</span>", $res);
  179.     print $res;
  180. }
  181.  
  182. function PrintNumResults($num)
  183. {
  184.     global $STR_NO_RESULTS, $STR_RESULT, $STR_RESULTS;
  185.     if ($num == 0)
  186.         return $STR_NO_RESULTS;
  187.     else if ($num == 1)
  188.         return $num . " " . $STR_RESULT;
  189.     else
  190.         return $num . " " . $STR_RESULTS;
  191. }
  192.  
  193. // ----------------------------------------------------------------------------
  194. // Compares the two values, used for sorting output results
  195. // Results that match all search terms are put first, highest score
  196. // ----------------------------------------------------------------------------
  197. function SortCompare ($a, $b)
  198. {
  199.     if ($a[2] < $b[2])
  200.         return 1;
  201.     else
  202.     if ($a[2] > $b[2])
  203.         return -1;
  204.     else
  205.     {
  206.         if ($a[1] < $b[1])
  207.             return 1;
  208.         else
  209.         if ($a[1] > $b[1])
  210.             return -1;
  211.         else
  212.             return 0;
  213.     }
  214. }
  215.  
  216. function SortByDate ($a, $b)
  217. {
  218.     global $datetime;
  219.     if ($datetime[$a[0]] < $datetime[$b[0]])
  220.         return 1;
  221.     else
  222.     if ($datetime[$a[0]] > $datetime[$b[0]])
  223.         return -1;
  224.     else
  225.     {
  226.         // if equal dates/time, return based on sw matched and score
  227.         return SortCompare($a, $b);
  228.     }
  229. }
  230.  
  231. // ----------------------------------------------------------------------------
  232. // Translates a typical shell wildcard pattern ("zoo*" => "zoom" etc.)
  233. // to a regular expression pattern. Supports only '*' and '?' characters.
  234. // ----------------------------------------------------------------------------
  235. function pattern2regexp($pattern)
  236. {
  237.     global $SearchAsSubstring;
  238.     global $ToLowerSearchWords;
  239.     $i = 0;
  240.     $len = strlen($pattern);
  241.  
  242.     if (strpos($pattern, "$") !== false)
  243.         str_replace($pattern, "$", "\$");
  244.     if (strpos($pattern, "#") !== false)
  245.         str_replace($pattern, "#", "\#");
  246.  
  247.     $res = "";
  248.  
  249.     while ($i < $len) {
  250.         $c = $pattern[$i];
  251.         if ($c == '*')
  252.             $res = $res . "[\d\S]*";
  253.         else
  254.         if ($c == '?')
  255.             $res = $res . ".";
  256.         else
  257.         if ($c == '.')
  258.             $res = $res . "\.";
  259.         else
  260.             $res = $res . preg_quote($c, '/');
  261.         $i++;
  262.     }
  263.     return $res;
  264. }
  265.  
  266. function GetDictID($word)
  267. {
  268.     global $dict;
  269.     global $dict_count;
  270.     for ($i = 0; $i < $dict_count; $i++) {
  271.         if (strcasecmp($dict[$i][0], $word) == 0)
  272.             return $i;
  273.     }
  274.     return -1;  // not found
  275. }
  276.  
  277. function GetNextDictWord($fp_pagetext)
  278. {
  279.     $word_id = 0;
  280.     do
  281.     {
  282.         $bytes_buffer = fread($fp_pagetext, 2); // grab 2 bytes
  283.         $dict_id = ord($bytes_buffer[0]) | ord($bytes_buffer[1])<<8;
  284.         $word_id += $dict_id;
  285.     } while ($dict_id >= 65535);
  286.     return $word_id;
  287. }
  288.  
  289. function SkipSearchWord($sw) {
  290.     global $SearchWords;
  291.     global $SkippedWords;
  292.     global $SkippedOutputStr;
  293.  
  294.     if ($SearchWords[$sw] != "") {
  295.         if ($SkippedWords > 0)
  296.             $SkippedOutputStr .= ", ";
  297.         $SkippedOutputStr .= "\"<b>" . $SearchWords[$sw] . "</b>\"";
  298.         $SearchWords[$sw] = "";
  299.     }
  300.     $SkippedWords++;
  301. }
  302.  
  303. function GetSPCode($word)
  304. {
  305.     $tmpword = strtolower($word);
  306.  
  307.     // strip out non alphabetic characters
  308.     $tmpword = preg_replace("/[^a-z]/", "", $tmpword);
  309.  
  310.     $wordlen = strlen($tmpword);
  311.     if ($wordlen < 1)
  312.         return "";
  313.  
  314.     $spcode = $tmpword[0];
  315.  
  316.     $tmpword = substr($tmpword, 1);
  317.     $tmpword = str_replace("a", "0", $tmpword);
  318.     $tmpword = str_replace("e", "0", $tmpword);
  319.     $tmpword = str_replace("i", "0", $tmpword);
  320.     $tmpword = str_replace("o", "0", $tmpword);
  321.     $tmpword = str_replace("u", "0", $tmpword);
  322.     $tmpword = str_replace("h", "0", $tmpword);
  323.     $tmpword = str_replace("w", "0", $tmpword);
  324.     $tmpword = str_replace("y", "0", $tmpword);
  325.  
  326.     $tmpword = str_replace("b", "1", $tmpword);
  327.     $tmpword = str_replace("p", "1", $tmpword);
  328.     $tmpword = str_replace("f", "1", $tmpword);
  329.     $tmpword = str_replace("v", "1", $tmpword);
  330.  
  331.     $tmpword = str_replace("c", "2", $tmpword);
  332.     $tmpword = str_replace("g", "2", $tmpword);
  333.     $tmpword = str_replace("j", "2", $tmpword);
  334.     $tmpword = str_replace("k", "2", $tmpword);
  335.     $tmpword = str_replace("q", "2", $tmpword);
  336.     $tmpword = str_replace("s", "2", $tmpword);
  337.     $tmpword = str_replace("x", "2", $tmpword);
  338.     $tmpword = str_replace("z", "2", $tmpword);
  339.  
  340.     $tmpword = str_replace("d", "3", $tmpword);
  341.     $tmpword = str_replace("t", "3", $tmpword);
  342.  
  343.     $tmpword = str_replace("l", "4", $tmpword);
  344.  
  345.     $tmpword = str_replace("m", "5", $tmpword);
  346.     $tmpword = str_replace("m", "5", $tmpword);
  347.  
  348.     $tmpword = str_replace("r", "6", $tmpword);
  349.  
  350.     // Remove any adjacent digits
  351.     $char = "";
  352.     $nextChar = "";
  353.     $tmpstr = "";
  354.     for ($i = 0; $i < $wordlen; $i++)
  355.     {
  356.         $char = substr($tmpword, $i, 1);
  357.         $nextChar = substr($tmpword, $i+1, 1);
  358.         if (is_numeric($char) && $char != $nextChar)
  359.             $tmpstr = $tmpstr . $char;
  360.     }
  361.     $tmpword = $tmpstr;
  362.  
  363.     if (strlen($tmpword) < 1)
  364.         return "";
  365.  
  366.     $tmpword = str_replace("0", "", $tmpword);
  367.  
  368.     // zero pad it out 4 characters
  369.     $tmpword = str_pad($tmpword, 4, "0");
  370.  
  371.     $spcode = $spcode . substr($tmpword, 0, 3);
  372.  
  373.     return $spcode;
  374. }
  375.  
  376. // ----------------------------------------------------------------------------
  377. // Starts here
  378. // ----------------------------------------------------------------------------
  379.  
  380. if ($Timing == 1 || $Logging == 1) {
  381.     $mtime = explode(" ", microtime());
  382.     $starttime = doubleval($mtime[1]) + doubleval($mtime[0]);
  383. }
  384.  
  385. //Open and print start of result page template
  386. $template = file ($TemplateFilename);
  387. $numtlines = count ($template); //Number of lines in the template
  388. $template_line = 0;
  389. while ($template_line < $numtlines)
  390. {
  391.     if (!stristr($template[$template_line], "<!--ZOOMSEARCH-->")) {
  392.         print($template[$template_line]);
  393.         $template_line++;
  394.     }
  395.     else {
  396.         break;
  397.     }
  398. }
  399. $template_line++;
  400.  
  401. if ($UseCats)
  402. {
  403.     if (file_exists("zoom_cats.zdat") && file_exists("zoom_catpages.zdat"))
  404.     {
  405.         $catnames = file("zoom_cats.zdat");
  406.         $catpages = file("zoom_catpages.zdat");
  407.     }
  408.     else
  409.     {
  410.         print("Zoom config error: Missing file(s) zoom_cats.zdat and zoom_catpages.zdat required for category enabled search mode");
  411.         return;
  412.     }
  413. }
  414. print("<!--Zoom Search Engine ".$Version."-->\n");
  415.  
  416. // Replace the key text <!--ZOOMSEARCH--> with the following
  417. if ($FormFormat > 0)
  418. {
  419.     // Insert the form
  420.     print("<form method=\"get\" action=\"".$SelfURL."\" class=\"zoom_searchform\">\n");
  421.     print($STR_FORM_SEARCHFOR . " <input type=\"text\" name=\"zoom_query\" size=\"20\" value=\"".htmlspecialchars($query)."\" class=\"zoom_searchbox\" />\n");
  422.     print("<input type=\"submit\" value=\"" . $STR_FORM_SUBMIT_BUTTON . "\" class=\"zoom_button\" />\n");
  423.     if ($FormFormat == 2) {
  424.         print("<span class=\"zoom_options\">" . $STR_FORM_RESULTS_PER_PAGE . "\n");
  425.         print("<select name='zoom_per_page'>\n");
  426.         reset($PerPageOptions);
  427.         foreach ($PerPageOptions as $ppo) {
  428.             print("<option");
  429.             if ($ppo == $per_page)
  430.                 print(" selected=\"selected\"");
  431.             print(">". $ppo ."</option>\n");
  432.         }
  433.         print("</select>\n<br /><br />\n");
  434.         if ($UseCats) {
  435.             print($STR_FORM_CATEGORY . " ");
  436.             print("<select name='zoom_cat'>");
  437.             // 'all cats option
  438.             print("<option value=\"-1\">" . $STR_FORM_CATEGORY_ALL . "</option>");
  439.             for($i = 0; $i < count($catnames); $i++) {
  440.                 print("<option value=\"". $i . "\"");
  441.                 if ($i == $cat)
  442.                     print(" selected=\"selected\"");
  443.                 print(">". $catnames[$i] . "</option>");
  444.             }
  445.             print("</select>  \n");
  446.         }
  447.         print($STR_FORM_MATCH . "\n");
  448.         if ($and == 0) {
  449.             print("<input type=\"radio\" name=\"zoom_and\" value=\"0\" checked=\"checked\" />" . $STR_FORM_ANY_SEARCH_WORDS . "\n");
  450.             print("<input type=\"radio\" name=\"zoom_and\" value=\"1\" />" . $STR_FORM_ALL_SEARCH_WORDS . "\n");
  451.         } else {
  452.             print("<input type=\"radio\" name=\"zoom_and\" value=\"0\" />" . $STR_FORM_ANY_SEARCH_WORDS . "\n");
  453.             print("<input type=\"radio\" name=\"zoom_and\" value=\"1\" checked=\"checked\" />" . $STR_FORM_ALL_SEARCH_WORDS . "\n");
  454.         }
  455.         print("<input type=\"hidden\" name=\"zoom_sort\" value=\"" . $sort . "\" />\n");
  456.         print("</span>\n");
  457.     }
  458.     else
  459.     {
  460.         print("<input type=\"hidden\" name=\"zoom_per_page\" value=\"" . $per_page . "\" />\n");
  461.         print("<input type=\"hidden\" name=\"zoom_and\" value=\"" . $and . "\" />\n");
  462.         print("<input type=\"hidden\" name=\"zoom_sort\" value=\"" . $sort . "\" />\n");
  463.     }
  464.     print("</form>\n");
  465. }
  466.  
  467. // Give up early if no search words provided
  468. if (empty($query))
  469. {
  470.     // only display 'no query' line if no form is shown
  471.     if ($FormFormat == 0)
  472.         print($STR_NO_QUERY . "<br />");
  473.  
  474.     PrintEndOfTemplate($template);
  475.     return;
  476. }
  477.  
  478. // Load index data files (*.zdat) ---------------------------------------------
  479.  
  480. // Load the entire pages file into an array, all URL's on the site
  481. $urls = file('zoom_pages.zdat');
  482.  
  483. // Load the entire page titles file into an array
  484. $titles = file('zoom_titles.zdat');
  485.  
  486. if ($DisplayMetaDesc == 1)
  487. {
  488.     $descriptions = file('zoom_descriptions.zdat');
  489.     if ($descriptions[0] == "This file blank due to indexing configuration.")
  490.     {
  491.         print("<b>Zoom config error:</b> The zoom_descriptions.zdat file is not properly created for the search settings specified.<br />Please check that you have re-indexed your site with the search settings selected in the configuration window.<br />");
  492.         return;
  493.     }
  494. }
  495.  
  496. // Open datetime file
  497. if ($UseDateTime == 1 || $DisplayDate == 1)
  498. {
  499.     $fp_datetime = fopen ("zoom_datetime.zdat", "rt");
  500.     $i = 0;
  501.     while (!feof($fp_datetime) && $i < $NumPages)
  502.     {
  503.         $dateline = fgets($fp_datetime, $MaxKeyWordLineLen);
  504.         if (strlen($dateline) > 0)
  505.         {
  506.             $datetime[$i] = strtotime($dateline);
  507.             $i++;
  508.         }
  509.     }
  510.     if ($i < $NumPages)
  511.     {
  512.         print("<b>Zoom config error</b>: The zoom_datetime.zdat file is invalid or not up-to-date. Please make sure you have uploaded all files from the same indexing session.<br />");
  513.         $UseDateTime = 0;
  514.     }
  515.     fclose($fp_datetime);
  516. }
  517.  
  518. // Open pagetext file
  519. if ($DisplayContext == 1 || $AllowExactPhrase == 1)
  520. {
  521.     $fp_pagetext = fopen("zoom_pagetext.zdat", "rb");
  522.     $teststr = fgets($fp_pagetext, 8);
  523.     if ($teststr[0] == "T" && $teststr[2] == "h" && $teststr[4] == "i" && $teststr[6] == "s")
  524.     {
  525.         print("<b>Zoom config error:</b> The zoom_pagetext.zdat file is not properly created for the search settings specified.<br />Please check that you have re-indexed your site with the search settings selected in the configuration window.<br />");
  526.         fclose($fp_pagetext);
  527.         return;
  528.     }
  529. }
  530.  
  531. //Open keywords file
  532. $fp_wordmap = fopen ("zoom_wordmap.zdat", "rb");
  533. if ($urls == FALSE || $titles == FALSE || $fp_wordmap == FALSE)
  534. {
  535.     print($STR_ERR_MISSING_ZDAT_FILES);
  536.     return;
  537. }
  538. $fp_dict = fopen("zoom_dictionary.zdat", "rt");
  539. $i = 0;
  540. while (!feof($fp_dict))
  541. {
  542.     $dictline = fgets($fp_dict, $MaxKeyWordLineLen);
  543.     if (strlen($dictline) > 0)
  544.     {
  545.         $dict[$i] = explode(" ", $dictline, 2);
  546.         $i++;
  547.     }
  548. }
  549. fclose($fp_dict);
  550. $dict_count = $i;
  551.  
  552. // Prepare query for search ---------------------------------------------------
  553.  
  554. if ($MapAccents == 1) {
  555.     $query = str_replace($AccentChars, $NormalChars, $query);
  556. }
  557.  
  558. if ($ToLowerSearchWords == 1)
  559. {
  560.     if ($UseUTF8 == 1 && function_exists('mb_strtolower'))
  561.         $query = mb_strtolower($query, "UTF-8");
  562.     else
  563.         $query = strtolower($query);
  564. }
  565.  
  566. // prepare search query, strip quotes, trim whitespace
  567. if ($AllowExactPhrase == 0)
  568. {
  569.     $query = str_replace("\"", " ", $query);
  570. }
  571. if (strspn(".", $WordJoinChars) == 0)
  572.     $query = str_replace(".", " ", $query);
  573.  
  574. if (strspn("-", $WordJoinChars) == 0)
  575.     $query = str_replace("-", " ", $query);
  576.  
  577. if (strspn("_", $WordJoinChars) == 0)
  578.     $query = str_replace("_", " ", $query);
  579.  
  580. if (strspn("'", $WordJoinChars) == 0)
  581.     $query = str_replace("'", " ", $query);
  582.  
  583. if (strspn("#", $WordJoinChars) == 0)
  584.     $query = str_replace("#", " ", $query);
  585.  
  586. if (strspn("$", $WordJoinChars) == 0)
  587.     $query = str_replace("$", " ", $query);
  588.  
  589. if (strspn(",", $WordJoinChars) == 0)
  590.     $query = str_replace(",", " ", $query);
  591.  
  592. // strip slashes, sloshes, consecutive spaces, parenthesis, etc.
  593. $query = preg_replace("/[\/\s\\\\(\)\^\[\]\|\+\{\}]+/", " ", $query); 
  594. $query = trim($query);
  595.  
  596. //Split search phrase into words
  597. preg_match_all("/\"(.*?)\"|[^\\s\"]+/", $query, $SearchWords);
  598. $SearchWords = preg_replace("/\"[\s]+|[\s]+\"|\"/", "", $SearchWords[0]);
  599.  
  600.  
  601. //Print heading
  602. print("<div class=\"searchheading\">" . $STR_RESULTS_FOR . " " . htmlspecialchars($query));
  603. if ($UseCats) {
  604.     if ($cat == -1)
  605.         print(" " . $STR_RESULTS_IN_ALL_CATEGORIES);
  606.     else
  607.         print(" " . $STR_RESULTS_IN_CATEGORY . " \"". rtrim($catnames[$cat]) . "\"");
  608. }
  609. print "</div><br />\n";
  610.  
  611. print "<div class=\"results\">\n";
  612.  
  613. // Begin main search loop -----------------------------------------------------
  614.  
  615. $numwords = count ($SearchWords);
  616. $pagesCount = count($urls);
  617. $outputline = 0;
  618. $matches = 0;
  619. $UseWildCards = 1;  // default as using wildcard
  620.  
  621.  
  622. // initialise $res_table to be a 2D array of count($pages) long, filled with zeros.
  623. if (function_exists('array_fill'))
  624.     $res_table = array_fill(0, $pagesCount, array_fill(0, 6, 0));
  625. else {
  626.     $res_table = array();
  627.     for ($i = 0; $i < $pagesCount; $i++) {
  628.         $res_table[$i] = array();
  629.         $res_table[$i][0] = 0;  // score
  630.         $res_table[$i][1] = 0;  // num of sw matched
  631.         $res_table[$i][2] = 0;  // pagetext ptr #1
  632.         $res_table[$i][3] = 0;  // pagetext ptr #2
  633.         $res_table[$i][4] = 0;  // pagetext ptr #3
  634.         $res_table[$i][5] = 0;  // 'and' user search terms matched
  635.     }
  636. }
  637.  
  638. // check if word is in skipword file
  639. $SkippedWords = 0;
  640. $context_maxgoback = 1;
  641. $SkippedExactPhrase = 0;
  642.  
  643. $maxscore = 0;
  644.  
  645. for ($sw = 0; $sw < $numwords; $sw++) {
  646.  
  647.     if ($SearchWords[$sw] == "")
  648.         continue;
  649.  
  650.     // check min length
  651.     if (strlen($SearchWords[$sw]) < $MinWordLen) {
  652.         SkipSearchWord($sw);
  653.         continue;
  654.     }
  655.  
  656.     $ExactPhrase = 0;
  657.     $UseWildCards = 0;
  658.     if ($AllowExactPhrase == 1 && strpos($SearchWords[$sw], " ") !== false)
  659.     {
  660.         // Initialise exact phrase matching for this search term
  661.         $ExactPhrase = 1;
  662.         $phrase_terms = split(" ", $SearchWords[$sw]);
  663.         //$phrase_terms = preg_split("/\W+/", $SearchWords[$sw], -1, 0 /*PREG_SPLIT_DELIM_CAPTURE*/);
  664.         $num_phrase_terms = count($phrase_terms);
  665.         if ($num_phrase_terms > $context_maxgoback)
  666.             $context_maxgoback = $num_phrase_terms;
  667.  
  668.         $phrase_terms_data = array();
  669.         $tmpid = 0;
  670.         $WordNotFound = 0;
  671.         for ($j = 0; $j < $num_phrase_terms; $j++)
  672.         {
  673.             $tmpid = GetDictID($phrase_terms[$j]);
  674.             if ($tmpid == -1)   // word is not in dictionary
  675.             {
  676.                 $WordNotFound = 1;
  677.                 break;
  678.             }
  679.  
  680.             $wordmap_row = $dict[$tmpid][1];
  681.             if ($wordmap_row != -1)
  682.             {
  683.                 fseek($fp_wordmap, $wordmap_row);
  684.                 $countbytes = fread($fp_wordmap, 2);
  685.                 $phrase_data_count[$j] = ord($countbytes[0]) | ord($countbytes[1])<<8;
  686.                 for ($xbi = 0; $xbi < $phrase_data_count[$j]; $xbi++) {
  687.                     $xbindata = fread($fp_wordmap, 8);
  688.                     if (strlen($xbindata) == 0)
  689.                         print "error in wordmap file: expected data not found";
  690.                     $phrase_terms_data[$j][$xbi] = unpack("vscore/vpagenum/Vptr", $xbindata);
  691.                 }
  692.             }
  693.             else
  694.             {
  695.                 $phrase_data_count[$j] = 0;
  696.                 $phrase_terms_data[$j] = 0;
  697.             }
  698.         }
  699.         if ($WordNotFound == 1)
  700.             continue;
  701.     }
  702.     else if (strpos($SearchWords[$sw], "*") !== false || strpos($SearchWords[$sw], "?") !== false)
  703.     {
  704.         $pattern = "/";
  705.  
  706.         // match entire word
  707.         if ($SearchAsSubstring == 0)
  708.             $pattern = $pattern . "\A";
  709.  
  710.         $SearchWords[$sw] = pattern2regexp($SearchWords[$sw]);
  711.         $pattern = $pattern . $SearchWords[$sw];
  712.  
  713.         if ($SearchAsSubstring == 0)
  714.             $pattern = $pattern . "\Z";
  715.  
  716.         if ($ToLowerSearchWords != 0)
  717.             $pattern = $pattern . "/i";
  718.         else
  719.             $pattern = $pattern . "/";
  720.  
  721.         $UseWildCards = 1;
  722.     }
  723.  
  724.     for ($i = 0; $i < $dict_count; $i++)
  725.     {
  726.         $dictline = $dict[$i];
  727.         $word = $dict[$i][0];
  728.  
  729.         // if we're not using wildcards, direct match
  730.         if ($ExactPhrase == 1)
  731.         {
  732.             // todo: move to next phrase term if first phrase term is skipped?
  733.             // compare first term in exact phrase
  734.             $result = strcasecmp($phrase_terms[0], $word);
  735.         }
  736.         else if ($UseWildCards == 0)
  737.         {
  738.             if ($SearchAsSubstring == 0)
  739.                 $result = strcasecmp($SearchWords[$sw], $word);
  740.             else
  741.             {
  742.                 if (stristr($word, $SearchWords[$sw]) == FALSE)
  743.                     $result = 1;    // not matched
  744.                 else
  745.                     $result = 0;    // matched
  746.             }
  747.         } else {
  748.             // if we have wildcards...
  749.             $result = !(preg_match($pattern, $word));
  750.         }
  751.         // result = 0 if matched, result != 0 if not matched.
  752.  
  753.         // word found but indicated to be not indexed or skipped
  754.         if ($result == 0 && $dictline[1] == -1)
  755.         {
  756.             if ($UseWildCards == 0 && $SearchAsSubstring == 0)
  757.             {
  758.                 if ($ExactPhrase == 1)
  759.                     $SkippedExactPhrase = 1;
  760.  
  761.                 SkipSearchWord($sw);
  762.                 break;
  763.             }
  764.             else
  765.                 continue;
  766.         }
  767.  
  768.         if ($result == 0)
  769.         {
  770.             // keyword found in the dictionary
  771.  
  772.             if ($ExactPhrase == 1)
  773.             {
  774.                 // we'll use the wordmap data for the first term that we have worked out earlier
  775.                 $data = $phrase_terms_data[0];
  776.                 $data_count = $phrase_data_count[0];
  777.                 $ContextSeeks = 0;
  778.             }
  779.             else
  780.             {
  781.                 // seek to position in wordmap file
  782.                 fseek($fp_wordmap, $dictline[1]);
  783.                 //print "seeking in wordmap: " . $dictline[1] . "<br />";
  784.  
  785.                 // first 2 bytes is data count
  786.                 $countbytes = fread($fp_wordmap, 2);
  787.                 $data_count = ord($countbytes[0]) | ord($countbytes[1])<<8;
  788.                 //print "data count: " . $data_count . "<br />";
  789.  
  790.                 for ($bi = 0; $bi < $data_count; $bi++)
  791.                 {
  792.                     $bindata = fread($fp_wordmap, 8);
  793.                     if (strlen($bindata) == 0)
  794.                         print "Error in wordmap file: expected data not found";
  795.                     $data[$bi] = unpack("vscore/vpagenum/Vptr", $bindata);
  796.                 }
  797.             }
  798.  
  799.             // Go through wordmap for each page this word appears on
  800.             for ($j = 0; $j < $data_count; $j++)
  801.             {
  802.                 $score = $data[$j]["score"];
  803.                 $txtptr = $data[$j]["ptr"];
  804.  
  805.                 if ($ExactPhrase == 1)
  806.                 {
  807.                     $maxptr = $data[$j]["ptr"];
  808.                     $maxptr_term = 0;
  809.                     $GotoNextPage = 0;
  810.  
  811.                     // Check if all of the other words in the phrase appears on this page.
  812.                     for ($xi = 1; $xi < $num_phrase_terms; $xi++)
  813.                     {
  814.                         // see if this word appears at all on this page, if not, we stop scanning page.
  815.                         // do not check for skipped words (data count value of zero)
  816.                         if ($phrase_data_count[$xi] != 0)
  817.                         {
  818.                             // check wordmap for this search phrase to see if it appears on the current page.
  819.                             for ($xbi = 0; $xbi < $phrase_data_count[$xi]; $xbi++) {
  820.                                 if ($phrase_terms_data[$xi][$xbi]["pagenum"] == $data[$j]["pagenum"])
  821.                                 {
  822.                                     // intersection, this term appears on both pages, goto next term
  823.                                     // remember biggest pointer.
  824.                                     if ($phrase_terms_data[$xi][$xbi]["ptr"] > $maxptr)
  825.                                     {
  826.                                         $maxptr = $phrase_terms_data[$xi][$xbi]["ptr"];
  827.                                         $maxptr_term = $xi;
  828.                                     }
  829.                                     $score += $phrase_terms_data[$xi][$xbi]["score"];
  830.                                     break;
  831.                                 }
  832.                             }
  833.                             if ($xbi == $phrase_data_count[$xi]) // if not found
  834.                             {
  835.                                 $GotoNextPage = 1;
  836.                                 break;  // goto next page
  837.                             }
  838.                         }
  839.                     }   // end phrase term for loop
  840.                     if ($GotoNextPage == 1)
  841.                         continue;
  842.  
  843.                     // Check how many context seeks we have made.
  844.                     $ContextSeeks++;
  845.                     if ($ContextSeeks > $MaxContextSeeks)
  846.                     {
  847.                         print "<small>" . $STR_PHRASE_CONTAINS_COMMON_WORDS . " <b>\"" . $SearchWords[$sw] . "\"</b></small><br /><br />";
  848.                         break;
  849.                     }
  850.  
  851.                     // ok, so this page contains all of the words in the phrase
  852.                     $FoundPhrase = 0;
  853.                     $FoundFirstWord = 0;
  854.  
  855.                     // we goto the first occurance of the first word in pagetext
  856.                     $pos = $maxptr - (($maxptr_term+3) * $MaxDictIDLen);    // assume 3 possible punctuations.
  857.                     // do not seek further back than the occurance of the first word (avoid wrong page)
  858.                     if ($pos < $data[$j]["ptr"])
  859.                         $pos = $data[$j]["ptr"];
  860.  
  861.                     fseek($fp_pagetext, $pos);
  862.  
  863.                     // now we look for the phrase within the context of this page
  864.                     do
  865.                     {
  866.                         for ($xi = 0; $xi < $num_phrase_terms; $xi++)
  867.                         {
  868.                             // do...while loop to ignore punctuation marks in context phrase
  869.                             do
  870.                             {
  871.                                 $xword_id = 0;
  872.                                 $bytesread = 0;
  873.                                 do
  874.                                 {
  875.                                     $bytes_buffer = fread($fp_pagetext, 2); // grab 2 bytes
  876.                                     $dict_id = ord($bytes_buffer[0]) | ord($bytes_buffer[1])<<8;
  877.                                     $xword_id += $dict_id;
  878.                                     $bytesread += 2;
  879.                                 } while ($dict_id >= 65535);
  880.  
  881.                                 $pos += $bytesread;
  882.  
  883.                                 // check if we are at the end of page (wordid = 0) or invalid $xword_id
  884.                                 if ($xword_id == 0 || $xword_id >= $dict_count)
  885.                                     break;
  886.                             } while ($xword_id <= $DictReservedLimit && !feof($fp_pagetext));
  887.  
  888.                             // if the words are NOT the same, we break out
  889.                             if (strcasecmp($dict[$xword_id][0], $phrase_terms[$xi]) != 0)
  890.                                 break;
  891.  
  892.                             // remember how many times we find the first word on this page
  893.                             if ($xi == 0)
  894.                             {
  895.                                 $FoundFirstWord++;
  896.                                 // remember the position of the 'start' of this phrase
  897.                                 //$txtptr = $pos - $MaxDictIDLen;
  898.                                 $txtptr = $pos - $bytesread;
  899.                             }
  900.                         }
  901.                         if ($xi == $num_phrase_terms)
  902.                         {
  903.                             // exact phrase found!
  904.                             $FoundPhrase = 1;
  905.                         }
  906.                     } while ($xword_id != 0 && $FoundPhrase == 0 &&
  907.                             $FoundFirstWord <= $data[$j]["score"]);
  908.  
  909.                     if ($FoundPhrase != 1)
  910.                         continue;   // goto next page.
  911.                 }
  912.  
  913.                 //Check if page is already in output list
  914.                 $pageexists = 0;
  915.                 $ipage = $data[$j]["pagenum"];
  916.  
  917.                 if ($res_table[$ipage][0] == 0)
  918.                 {
  919.                     // not in list, count this page as a unique match
  920.                     $matches++;
  921.                     $res_table[$ipage][0] += $score;
  922.                     $res_table[$ipage][2] = $txtptr;
  923.                 }
  924.                 else
  925.                 {
  926.                     // already in list
  927.                     if ($res_table[$ipage][0] > 10000)
  928.                     {
  929.                         // take it easy if its too big (to prevent huge scores)
  930.                         $res_table[$ipage][0] += 1;
  931.                     }
  932.                     else
  933.                     {
  934.                         $res_table[$ipage][0] += $score;    //Add in score
  935.                         $res_table[$ipage][0] *= 2;               //Double Score as we have two words matching
  936.                     }
  937.  
  938.                     // store the next two searchword matches
  939.                     if ($res_table[$ipage][1] > 0 && $res_table[$ipage][1] < $MaxContextKeywords)
  940.                     {
  941.                         if ($res_table[$ipage][3] == 0)
  942.                             $res_table[$ipage][3] = $txtptr;
  943.                         elseif ($res_table[$ipage][4] == 0)
  944.                             $res_table[$ipage][4] = $txtptr;
  945.                     }
  946.                 }
  947.                 $res_table[$ipage][1] += 1;
  948.  
  949.                 if ($res_table[$ipage][0] > $maxscore)
  950.                     $maxscore = $res_table[$ipage][0];
  951.  
  952.                 // store the 'and' user search terms matched' value
  953.                 if ($res_table[$ipage][5] == $sw || $res_table[$ipage][5] == $sw-$SkippedWords)
  954.                     $res_table[$ipage][5] += 1;
  955.             }
  956.  
  957.             if ($UseWildCards == 0 && $SearchAsSubstring == 0)
  958.                 break;  //This search word was found, so skip to next
  959.         }
  960.     }
  961. }
  962. //Close the files
  963. fclose($fp_wordmap);
  964.  
  965. if ($SkippedWords > 0)
  966. {
  967.     print "<i>" . $STR_SKIPPED_FOLLOWING_WORDS . " " . $SkippedOutputStr . "<br />\n";
  968.     if ($SkippedExactPhrase == 1)
  969.         print $STR_SKIPPED_PHRASE . ".<br />\n";
  970.     print "</i><br />\n";
  971. }
  972.  
  973.  
  974.  
  975. //Count number of output lines that match ALL search terms
  976. $oline = 0;
  977. $fullmatches = 0;
  978.  
  979. // Second pass, results filtering.
  980. $ResFiltered = false;
  981. $full_numwords = $numwords - $SkippedWords;
  982. for ($i = 0; $i < $pagesCount; $i++)
  983. {
  984.     $IsFiltered = false;
  985.     if ($res_table[$i][0] != 0) {
  986.         if ($UseCats && $cat != -1) {
  987.             // Using cats and not doing an "all cats" search
  988.             if (rtrim($catpages[$i]) != $cat)
  989.                 $IsFiltered = true;
  990.         }
  991.         if ($IsFiltered == false) {
  992.             //if ($res_table[$i][1] >= $full_numwords)
  993.             if ($res_table[$i][5] >= $full_numwords)
  994.                 $fullmatches++;
  995.             else {
  996.                 // if AND search, only copy AND results
  997.                 if ($and == 1)
  998.                     $IsFiltered = true;
  999.             }
  1000.         }
  1001.  
  1002.         if ($IsFiltered == false) {
  1003.             // copy if not filtered out
  1004.             $output[$oline][0] = $i;                    // page index
  1005.             $output[$oline][1] = $res_table[$i][0];     // score
  1006.             $output[$oline][2] = $res_table[$i][1];     // num of sw matched
  1007.             $output[$oline][3] = $res_table[$i][2];     // pagetext ptr #1
  1008.             $output[$oline][4] = $res_table[$i][3];     // pagetext ptr #2
  1009.             $output[$oline][5] = $res_table[$i][4];     // pagetext ptr #3
  1010.             $oline++;
  1011.         } else {
  1012.             $ResFiltered = true;
  1013.         }
  1014.     }
  1015. }
  1016. if ($ResFiltered) {
  1017.     $matches = $oline;
  1018. }
  1019.  
  1020. //Sort results in order of score, use the "SortCompare" function
  1021. if ($matches > 1)
  1022. {
  1023.     if ($sort == 1 && $UseDateTime == 1 && isset($datetime))
  1024.     {
  1025.         usort($output, "SortByDate");
  1026.     }
  1027.     else
  1028.     {
  1029.         // Default sort by relevance
  1030.         usort($output, "SortCompare");
  1031.     }
  1032. }
  1033.  
  1034. // query_out is the query prepared to be passed in a URL.
  1035. //$query_out = htmlspecialchars($query_out);
  1036. $query_out = urlencode($query);
  1037.  
  1038. //Display search result information
  1039. print("<div class=\"summary\">\n");
  1040. if ($matches == 0)
  1041.     print $STR_SUMMARY_NO_RESULTS_FOUND;
  1042. elseif ($numwords > 1 && $and == 0)
  1043. {
  1044.     //OR
  1045.     $SomeTermMatches = $matches - $fullmatches;
  1046.     print PrintNumResults($fullmatches) . " " . $STR_SUMMARY_FOUND_CONTAINING_ALL_TERMS . " ";
  1047.     if ($SomeTermMatches > 0)
  1048.         print PrintNumResults($SomeTermMatches) . " " . $STR_SUMMARY_FOUND_CONTAINING_SOME_TERMS;
  1049. }
  1050. elseif ($numwords > 1 && $and == 1) //AND
  1051.     print PrintNumResults($fullmatches) . " " . $STR_SUMMARY_FOUND_CONTAINING_ALL_TERMS;
  1052. else
  1053.     print PrintNumResults($matches) . " " . $STR_SUMMARY_FOUND;
  1054.  
  1055. print "<br />";
  1056. if ($matches < 3)
  1057. {
  1058.     if ($and == 1 && $numwords > 1)
  1059.         print "<br />" . $STR_POSSIBLY_GET_MORE_RESULTS . " <a href=\"".$SelfURL."?zoom_query=".$query_out."&zoom_page=".$page."&zoom_per_page=".$per_page."&zoom_cat=".$cat."&zoom_and=0&zoom_sort=".$sort."\">". $STR_ANY_OF_TERMS . "</a>.<br />";
  1060.     else if ($UseCats && $cat != -1)
  1061.         print "<br />" . $STR_POSSIBLY_GET_MORE_RESULTS . " <a href=\"".$SelfURL."?zoom_query=".$query_out."&zoom_page=".$page."&zoom_per_page=".$per_page."&zoom_cat=-1&zoom_and=".$and."&zoom_sort=".$sort."\">" . $STR_ALL_CATS . "</a>.<br />";
  1062. }
  1063. print "</div>\n";
  1064.  
  1065. if ($Spelling == 1 && $matches < $SpellingWhenLessThan)
  1066. {
  1067.     // load in spellings file
  1068.     $fp_spell = fopen("zoom_spelling.zdat", "rt");
  1069.     $i = 0;
  1070.     while (!feof($fp_spell))
  1071.     {
  1072.         $spline = fgets($fp_spell, $MaxKeyWordLineLen);
  1073.         if (strlen($spline) > 0)
  1074.         {
  1075.             $spell[$i] = explode(" ", $spline, 2);
  1076.             $i++;
  1077.         }
  1078.     }
  1079.     fclose($fp_spell);
  1080.     $spell_count = $i;
  1081.  
  1082.     $SuggestStr = "";
  1083.     $SuggestionFound = 0;
  1084.     $SuggestionCount = 0;
  1085.  
  1086.     for ($sw = 0; $sw < $numwords; $sw++)
  1087.     {
  1088.         // word does not match, check if it is a candidate to be a suggestion
  1089.         $sw_spcode = GetSPCode($SearchWords[$sw]);
  1090.  
  1091.         if (strlen($sw_spcode) == 4)
  1092.         {
  1093.             $SuggestionFound = 0;
  1094.             for ($i = 0; $i < $spell_count; $i++)
  1095.             {
  1096.                 $spcode = $spell[$i][0];
  1097.                 $dictid = intval($spell[$i][1]);
  1098.  
  1099.                 $word = $dict[$dictid][0];
  1100.                 $ptr = $dict[$dictid][1];
  1101.  
  1102.                 if ($spcode == $sw_spcode)
  1103.                 {
  1104.                     if ($ptr == -1 || strcasecmp($word, $SearchWords[$sw]) == 0)
  1105.                     {
  1106.                         // Check that it is not a skipped word or the same word
  1107.                         $SuggestionFound = 0;
  1108.                         break;
  1109.                     }
  1110.                     else
  1111.                     {
  1112.                         $SuggestionFound = 1;
  1113.                         $SuggestionCount++;
  1114.                         break;
  1115.                     }
  1116.                 }
  1117.                 elseif (strcmp($spcode, $sw_spcode) > 0)
  1118.                 {
  1119.                     break;
  1120.                 }
  1121.  
  1122.                 if ($SuggestionFound == 1)
  1123.                     break;
  1124.             }
  1125.  
  1126.             if ($sw > 0)
  1127.                 $SuggestStr = $SuggestStr . " ";
  1128.  
  1129.             if ($SuggestionFound == 1)
  1130.                 $SuggestStr = $SuggestStr . $word;  // add string AFTER so we can preserve order of words
  1131.             else
  1132.                 $SuggestStr = $SuggestStr . $SearchWords[$sw];
  1133.         }
  1134.     }
  1135.  
  1136.     if ($SuggestionCount > 0)
  1137.     {
  1138.         print "<br />" . $STR_DIDYOUMEAN . " <a href=\"".$SelfURL."?zoom_query=".urlencode($SuggestStr)."&zoom_page=".$page."&zoom_per_page=".$per_page."&zoom_cat=".$cat."&zoom_and=0&zoom_sort=".$sort."\">". $SuggestStr . "</a>?<br />";
  1139.     }
  1140.  
  1141. }
  1142.  
  1143.  
  1144. // Number of pages of results
  1145. $num_pages = ceil($matches / $per_page);
  1146. if ($num_pages > 1)
  1147.     print "<br />" . $num_pages . " " . $STR_PAGES_OF_RESULTS . "<br />\n";
  1148.  
  1149. // Show sorting options
  1150. if ($matches > 1)
  1151. {
  1152.     if ($UseDateTime == 1)
  1153.     {
  1154.         print("<div class=\"sorting\">");
  1155.         if ($sort == 1)
  1156.             print("<a href=\"".$SelfURL."?zoom_query=".$query_out."&zoom_page=".$page."&zoom_per_page=".$per_page."&zoom_cat=".$cat."&zoom_and=".$and."&zoom_sort=0\">". $STR_SORTBY_RELEVANCE . "</a> / <b>". $STR_SORTEDBY_DATE . "</b>");
  1157.         else
  1158.             print("<b>". $STR_SORTEDBY_RELEVANCE . "</b> / <a href=\"".$SelfURL."?zoom_query=".$query_out."&zoom_page=".$page."&zoom_per_page=".$per_page."&zoom_cat=".$cat."&zoom_and=".$and."&zoom_sort=1\">". $STR_SORTBY_DATE . "</a>");
  1159.         print("</div>");
  1160.     }
  1161. }
  1162.  
  1163. // Determine current line of result from the $output array
  1164. if ($page == 1) {
  1165.     $arrayline = 0;
  1166. } else {
  1167.     $arrayline = (($page - 1) * $per_page);
  1168. }
  1169.  
  1170. // The last result to show on this page
  1171. $result_limit = $arrayline + $per_page;
  1172.  
  1173. // Display the results
  1174. while ($arrayline < $matches && $arrayline < $result_limit)
  1175. {
  1176.     $ipage = $output[$arrayline][0];
  1177.     $score = $output[$arrayline][1];
  1178.  
  1179.     print "<p></p>\n";
  1180.  
  1181.     print "<div class=\"result_title\">";
  1182.     if ($DisplayNumber == 1)
  1183.         print "<b>".($arrayline+1).".</b> ";
  1184.  
  1185.     if ($DisplayTitle == 1)
  1186.     {
  1187.         if ($GotoHighlight == 1)
  1188.         {
  1189.             if ($SearchAsSubstring == 1)
  1190.                 print "<a href=\"".rtrim($urls[$ipage])."?zoom_highlightsub=". $query_out . "\"" . $target . ">";
  1191.             else
  1192.                 print "<a href=\"".rtrim($urls[$ipage])."?zoom_highlight=". $query_out . "\"" . $target . ">";
  1193.         }        
  1194.         else        
  1195.             print "<a href=\"".rtrim($urls[$ipage])."\"" . $target . ">";
  1196.             
  1197.         if ($Highlighting == 1)
  1198.             PrintHighlightDescription(rtrim($titles[$ipage]));
  1199.         else
  1200.             print rtrim($titles[$ipage]);
  1201.         print "</a>";
  1202.     }
  1203.     else
  1204.         print "<a href=\"".rtrim($urls[$ipage])."\"" . $target . ">".rtrim($urls[$ipage])."</a>";
  1205.  
  1206.     if ($UseCats)
  1207.     {
  1208.         $catindex = rtrim($catpages[$ipage]);
  1209.         print " <span class=\"category\">[". rtrim($catnames[$catindex]) . "]</span>";
  1210.     }
  1211.     print "</div>\n";
  1212.  
  1213.     if ($DisplayMetaDesc == 1)
  1214.     {
  1215.         // Print meta description
  1216.         if (strlen($descriptions[$ipage]) > 2) {
  1217.             print("<div class=\"description\">");
  1218.             if ($Highlighting == 1)
  1219.                 PrintHighlightDescription(rtrim($descriptions[$ipage]));
  1220.             else
  1221.                 print rtrim($descriptions[$ipage]);
  1222.             print "<b>...</b></div>\n";
  1223.         }
  1224.     }
  1225.  
  1226.     if ($DisplayContext == 1)
  1227.     {
  1228.         // Extract contextual page content
  1229.         $context_keywords = $output[$arrayline][2]; // # of terms matched
  1230.         if ($context_keywords > $MaxContextKeywords)
  1231.             $context_keywords = $MaxContextKeywords;
  1232.  
  1233.         $context_word_count = ceil($ContextSize / $context_keywords);
  1234.  
  1235.         $goback = floor($context_word_count / 2);
  1236.         $gobackbytes = $goback * $MaxDictIDLen;
  1237.         if (($gobackbytes / 2) > ($context_word_count - $context_maxgoback - $goback))   // 2 is MinDictIDLen
  1238.         {
  1239.             // go back less if potential for matched word to be outside the context range
  1240.             // determine most bytes we should go back to fit the word in in case of all dict ID's were min. len.
  1241.             $gobackbytes = 2 * ($context_word_count - $context_maxgoback - $goback);
  1242.             // determine number of words available with this number of bytes, if all dict ID's were max. len.
  1243.             // thus avoiding jumping into the middle of a multi-pair dictID value
  1244.             $goback = floor($gobackbytes / $MaxDictIDLen);
  1245.             // redetermine max bytes to jump back for this number of words
  1246.             $gobackbytes = $goback * $MaxDictIDLen;
  1247.         }
  1248.  
  1249.         $last_startpos = 0;
  1250.         $last_endpos = 0;
  1251.  
  1252.         $FoundContext = 0;
  1253.  
  1254.         print "<div class=\"context\">\n";
  1255.         for ($j = 0; $j < $context_keywords && !feof($fp_pagetext); $j++)
  1256.         {
  1257.             $origpos = $output[$arrayline][3 + $j];
  1258.             $startpos = $origpos;
  1259.  
  1260.             if ($gobackbytes < $startpos)
  1261.             {
  1262.                 $startpos = $startpos - $gobackbytes;
  1263.                 $noGoBack = false;
  1264.             }
  1265.             else
  1266.                 $noGoBack = true;
  1267.  
  1268.             //if ($startpos < 0)
  1269.             //    $startpos = 0;
  1270.  
  1271.             // Check that this will not overlap with previous extract
  1272.             if ($startpos > $last_startpos && $startpos < $last_endpos)
  1273.                 $startpos = $last_endpos;   // we will just continue last extract if so.
  1274.  
  1275.             // find the pagetext pointed to
  1276.             fseek($fp_pagetext, $startpos);
  1277.  
  1278.             // remember the last start position
  1279.             $last_startpos = $startpos;
  1280.  
  1281.             $word_id = GetNextDictWord($fp_pagetext);
  1282.             //print "wordid: " . $word_id;
  1283.  
  1284.             $context_str = "";
  1285.  
  1286.             $noSpaceForNextChar = false;
  1287.  
  1288.             for ($i = 0; $i < $context_word_count && !feof($fp_pagetext); $i++)
  1289.             {
  1290.                 if ($noSpaceForNextChar == false)
  1291.                 {
  1292.                     //if ($word_id > $DictReservedLimit) // no space for reserved words (punctuation, etc)
  1293.                     // No space for reserved words (punctuation, etc)
  1294.                     if ($word_id > $DictReservedNoSpaces)
  1295.                         $context_str .= " ";
  1296.                     elseif  ($word_id > $DictReservedSuffixes && $word_id <= $DictReservedPrefixes)
  1297.                     {
  1298.                         // This is a Prefix character
  1299.                         $context_str .= " ";
  1300.                         $noSpaceForNextChar = true;
  1301.                     }
  1302.                     elseif ($word_id > $DictReservedPrefixes)   // this is a nospace character
  1303.                         $noSpaceForNextChar = true;
  1304.                 }
  1305.                 else
  1306.                     $noSpaceForNextChar = false;
  1307.  
  1308.                 if ($word_id == 0 || $word_id >= $dict_count)    // check if end of page
  1309.                 {
  1310.                     // if end of page occurs AFTER word pointer (ie: reached next page)
  1311.                     if ($noGoBack || ftell($fp_pagetext) > $origpos)
  1312.                         break;          // then we stop.
  1313.                     else                // if end of page occurs BEFORE word pointer (ie: reached previous page)
  1314.                     {
  1315.                         $context_str = "";// then we clear the existing context buffer we've created.
  1316.                         $i = 0;
  1317.                     }
  1318.                 }
  1319.                 else
  1320.                     $context_str .= $dict[$word_id][0];
  1321.  
  1322.                 $word_id = GetNextDictWord($fp_pagetext);
  1323.             }
  1324.  
  1325.             // remember the last end position
  1326.             $last_endpos = ftell($fp_pagetext);
  1327.  
  1328.             if (strcmp(trim($context_str), trim($titles[$ipage])) == 0)
  1329.             {
  1330.                 $context_str = ""; // clear the string if its identical to the title
  1331.             }
  1332.  
  1333.             if ($context_str != "")
  1334.             {
  1335.                 print " <b>...</b> ";
  1336.                 $FoundContext = 1;
  1337.                 if ($Highlighting == 1)
  1338.                     PrintHighlightDescription($context_str);
  1339.                 else
  1340.                     print $context_str;
  1341.             }
  1342.         }
  1343.         if ($FoundContext == 1)
  1344.             print " <b>...</b>";
  1345.         print "</div>\n";
  1346.     }
  1347.  
  1348.     $info_str = "";
  1349.  
  1350.     if ($DisplayTerms == 1)
  1351.     {
  1352.         $info_str .= $STR_RESULT_TERMS_MATCHED . " ". $output[$arrayline][2];
  1353.     }
  1354.  
  1355.     if ($DisplayScore == 1)
  1356.     {
  1357.         if (strlen($info_str) > 0)
  1358.             $info_str .= "  -  ";
  1359.         $info_str .= $STR_RESULT_SCORE . " " . $score;
  1360.     }
  1361.  
  1362.     if ($DisplayDate == 1)
  1363.     {
  1364.         if (strlen($info_str) > 0)
  1365.             $info_str .= "  -  ";
  1366.         //$info_str .= date("j M Y @ g:i A", $datetime[$ipage]) ."  -  ";
  1367.         $info_str .= date("j M Y", $datetime[$ipage]);
  1368.     }
  1369.  
  1370.     if ($DisplayURL == 1)
  1371.     {
  1372.         if (strlen($info_str) > 0)
  1373.             $info_str .= "  -  ";
  1374.         $info_str .= $STR_RESULT_URL . " ".rtrim($urls[$ipage]);
  1375.     }
  1376.  
  1377.     print "<div class=\"infoline\">";
  1378.     print $info_str;
  1379.     print "</div>\n";
  1380.     $arrayline++;
  1381. }
  1382.  
  1383. if ($DisplayContext == 1 || $AllowExactPhrase == 1)
  1384.     fclose($fp_pagetext);
  1385.  
  1386. // Show links to other result pages
  1387. if ($num_pages > 1) {
  1388.  
  1389.     // 10 results to the left of the current page
  1390.     $start_range = $page - 10;
  1391.     if ($start_range < 1)
  1392.         $start_range = 1;
  1393.  
  1394.     // 10 to the right
  1395.     $end_range = $page + 10;
  1396.     if ($end_range > $num_pages)
  1397.         $end_range = $num_pages;
  1398.  
  1399.     print "<p></p>\n" . $STR_RESULT_PAGES . " ";
  1400.     if ($page > 1)
  1401.         print "<a href=\"".$SelfURL."?zoom_query=".$query_out."&zoom_page=".($page-1)."&zoom_per_page=".$per_page."&zoom_cat=".$cat."&zoom_and=".$and."&zoom_sort=".$sort."\"><< " . $STR_RESULT_PAGES_PREVIOUS . "</a> ";
  1402.  
  1403.     for ($i = $start_range; $i <= $end_range; $i++) {
  1404.         if ($i == $page) {
  1405.             print $page." ";
  1406.         } else {
  1407.             print "<a href=\"".$SelfURL."?zoom_query=".$query_out."&zoom_page=".($i)."&zoom_per_page=".$per_page."&zoom_cat=".$cat."&zoom_and=".$and."&zoom_sort=".$sort."\">".$i."</a> ";
  1408.         }
  1409.     }
  1410.  
  1411.     if ($page != $num_pages)
  1412.         print "<a href=\"".$SelfURL."?zoom_query=".$query_out."&zoom_page=".($page+1)."&zoom_per_page=".$per_page."&zoom_cat=".$cat."&zoom_and=".$and."&zoom_sort=".$sort."\">" . $STR_RESULT_PAGES_NEXT . " >></a> ";
  1413. }
  1414. print "</div>"; // end of results style tag
  1415.  
  1416. if ($Timing == 1 || $Logging == 1) {
  1417.     $mtime = explode(" ", microtime());
  1418.     $endtime   = doubleval($mtime[1]) + doubleval($mtime[0]);
  1419.     $difference = abs($starttime - $endtime);
  1420.     $timetaken = number_format($difference, 3, '.', '');
  1421.     if ($Timing == 1)
  1422.         print "<br /><br /><small>" . $STR_SEARCH_TOOK . " " . $timetaken . " " . $STR_SECONDS . "</small><br />\n";
  1423. }
  1424.  
  1425. //Log the search words, if required
  1426. if ($Logging == 1)
  1427. {
  1428.     $LogQuery = str_replace("\"", "\"\"", $query);
  1429.     $LogString = Date("Y-m-d, H:i:s") . ", " . $_SERVER['REMOTE_ADDR'] . ", \"" .$LogQuery  . "\", Matches = " . $matches;
  1430.     if ($and == 1)
  1431.         $LogString = $LogString . ", AND";
  1432.     else
  1433.         $LogString = $LogString . ", OR";
  1434.  
  1435.     if ($NewSearch == 1)
  1436.         $page = 0;
  1437.  
  1438.     $LogString = $LogString . ", PerPage = " . $per_page . ", PageNum = " . $page;
  1439.  
  1440.     if ($UseCats == 0)
  1441.         $LogString = $LogString . ", No cats";
  1442.     else
  1443.     {
  1444.         if ($cat == -1)
  1445.             $LogString = $LogString . ", \"Cat = All\"";
  1446.         else
  1447.         {
  1448.             $logCatStr = trim($catnames[$cat]);
  1449.             $logCatStr = str_replace("\"", "\"\"", $logCatStr);
  1450.             $LogString = $LogString . ", \"Cat = " . $logCatStr . "\"";
  1451.         }
  1452.     }
  1453.     $LogString = $LogString . ", Time = " . $timetaken;
  1454.  
  1455.     // end of entry
  1456.     $LogString = $LogString . "\r\n";
  1457.  
  1458.     $fp = fopen ($LogFileName, "ab");
  1459.     if ($fp != false)
  1460.     {
  1461.         fputs ($fp, $LogString);
  1462.         fclose ($fp);
  1463.     }
  1464.     else
  1465.     {
  1466.         print "Unable to write to log file (" . $LogFileName . "). Check that you have specified the correct log filename in your Indexer settings and that you have the required file permissions set.<br />";
  1467.     }
  1468. }
  1469.  
  1470. //Print out the end of the template
  1471. PrintEndOfTemplate($template);
  1472.  
  1473.  
  1474. ?>
  1475.